{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 前言\n",
    "\n",
    "Python从设计之初就已经是一门面向对象的语言，正因为如此，在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。\n",
    "\n",
    "# 面向对象技术简介\n",
    "+ **类(Class):** 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。\n",
    "+ **方法：**类中定义的函数。\n",
    "+ **类变量：**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。\n",
    "+ **数据成员：**类变量或者实例变量用于处理类及其实例对象的相关的数据。\n",
    "+ **方法重写：**如果从父类继承的方法不能满足子类的需求，可以对其进行改写，这个过程叫方法的覆盖（override），也称为方法的重写。\n",
    "+ **局部变量：**定义在方法中的变量，只作用于当前实例的类。\n",
    "+ **实例变量：**在类的声明中，属性是用变量来表示的，这种变量就称为实例变量，实例变量就是一个用 self 修饰的变量。\n",
    "+ **继承：**即一个派生类（derived class）继承基类（base class）的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如，有这样一个设计：一个Dog类型的对象派生自Animal类，这是模拟\"是一个（is-a）\"关系（例图，Dog是一个Animal）。\n",
    "+ **实例化：**创建一个类的实例，类的具体对象。\n",
    "+ **对象：**通过类定义的数据结构实例。对象包括两个数据成员（类变量和实例变量）和方法。\n",
    "\n",
    "和其它编程语言相比，Python 在尽可能不增加新的语法和语义的情况下加入了类机制。\n",
    "\n",
    "Python中的类提供了面向对象编程的所有基本功能：类的继承机制允许多个基类，派生类可以覆盖基类中的任何方法，方法中可以调用基类中的同名方法。\n",
    "\n",
    "对象可以包含任意数量和类型的数据。\n",
    "\n",
    "# 类定义\n",
    "语法格式如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-1-800015dc0bd8>, line 2)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-1-800015dc0bd8>\"\u001b[0;36m, line \u001b[0;32m2\u001b[0m\n\u001b[0;31m    <statement-1>\u001b[0m\n\u001b[0m    ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "class ClassName:\n",
    "    <statement-1>\n",
    "    .\n",
    "    .\n",
    "    .\n",
    "    <statement-N>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类实例化后，可以使用其属性，实际上，创建一个类之后，可以通过类名访问其属性。\n",
    "\n",
    "# 类对象\n",
    "类对象支持两种操作：属性引用和实例化。\n",
    "\n",
    "属性引用使用和 Python 中所有的属性引用一样的标准语法：obj.name。\n",
    "\n",
    "类对象创建后，类命名空间中所有的命名都是有效属性名。所以如果类定义是这样:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MyClass 类的属性 i 为： 12345\n",
      "MyClass 类的方法 f 输出为： hello world\n"
     ]
    }
   ],
   "source": [
    "class MyClass:\n",
    "    \"\"\"一个简单的类实例\"\"\"\n",
    "    i = 12345\n",
    "    def f(self):\n",
    "        return 'hello world'\n",
    " \n",
    "# 实例化类\n",
    "x = MyClass()\n",
    " \n",
    "# 访问类的属性和方法\n",
    "print(\"MyClass 类的属性 i 为：\", x.i)\n",
    "print(\"MyClass 类的方法 f 输出为：\", x.f())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 解读\n",
    "以上创建了一个新的类实例并将该对象赋给局部变量 x，x 为空的对象。\n",
    "\n",
    "类有一个名为`__init__()`的特殊方法（构造方法），该方法在类实例化时会自动调用，像下面这样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def __init__(self):\n",
    "    self.data = []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类定义了 __init__() 方法，类的实例化操作会自动调用 __init__() 方法。如下实例化类 MyClass，对应的 __init__() 方法就会被调用:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = MyClass()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当然， __init__() 方法可以有参数，参数通过 __init__() 传递到类的实例化操作上。例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.0 -4.5\n"
     ]
    }
   ],
   "source": [
    "class Complex:\n",
    "    def __init__(self, realpart, imagpart):\n",
    "        self.r = realpart\n",
    "        self.i = imagpart\n",
    "x = Complex(3.0, -4.5)\n",
    "print(x.r, x.i)   # 输出结果：3.0 -4.5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## self代表类的实例，而非类\n",
    "类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Test object at 0x109b0c750>\n",
      "<class '__main__.Test'>\n"
     ]
    }
   ],
   "source": [
    "class Test:\n",
    "    def prt(self):\n",
    "        print(self)\n",
    "        print(self.__class__)\n",
    " \n",
    "t = Test()\n",
    "t.prt()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从执行结果可以很明显的看出，self 代表的是类的实例，代表当前对象的地址，而 self.class 则指向类。\n",
    "\n",
    "self 不是 python 关键字，我们把他换成 runoob 也是可以正常执行的:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Test object at 0x109b0ce50>\n",
      "<class '__main__.Test'>\n"
     ]
    }
   ],
   "source": [
    "class Test:\n",
    "    def prt(runoob):\n",
    "        print(runoob)\n",
    "        print(runoob.__class__)\n",
    " \n",
    "t = Test()\n",
    "t.prt()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 类的方法\n",
    "在类的内部，使用 `def` 关键字来定义一个方法，与一般函数定义不同，类方法必须包含参数 self, 且为第一个参数，self 代表的是类的实例。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "runoob 说: 我 10 岁。\n"
     ]
    }
   ],
   "source": [
    "#类定义\n",
    "class people:\n",
    "    #定义基本属性\n",
    "    name = ''\n",
    "    age = 0\n",
    "    #定义私有属性,私有属性在类外部无法直接进行访问\n",
    "    __weight = 0\n",
    "    #定义构造方法\n",
    "    def __init__(self,n,a,w):\n",
    "        self.name = n\n",
    "        self.age = a\n",
    "        self.__weight = w\n",
    "    def speak(self):\n",
    "        print(\"%s 说: 我 %d 岁。\" %(self.name,self.age))\n",
    " \n",
    "# 实例化类\n",
    "p = people('runoob',10,30)\n",
    "p.speak()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
